home *** CD-ROM | disk | FTP | other *** search
- /*
- File: FractalEngine.c
-
- Used to build: “Fractal 8”
-
- Written by: Jim Cathey July 1985
- Eric Traut November 1994
-
- Description:
- The following code implements a “Fractal Contour” generating
- program. See comments in the file “FractalMain.c” for more
- information.
-
- The code in this file implements the fractal-generating
- and plotting portion of the program.
- */
-
-
- #pragma cplusplus off
- #include <Quickdraw.h>
- #include <ToolUtils.h>
- #include <Timer.h>
-
- #include <stdlib.h>
-
- #include "Fractal.h"
-
- /* Functions defined within this file */
- static double RandomDouble(void);
- static void CalcXs(long len, long incr, long sk);
- static void CalcYs(long len, long incr, long sk);
- static void CalcDiagonals(long len, long incr, long sk);
- static long GetZValue(long x, long y);
- static long GetOldZValue(long x, long y);
- static void SetZValue(long d, long x, long y);
- static unsigned char GetLineColor(unsigned short red, unsigned short blue, unsigned short green);
- static void LineToOffscreen(long sX, long sY, long eX, long eY);
- static void LineXOffscreen(long startX, long startY, long endX, long endY);
- static void LineYOffscreen(long startX, long startY, long endX, long endY);
- static void PointOffscreen(long x, long y , unsigned char colorValue);
- static void SetGrayValues(void);
- static void Transform1Point(long xIndex, long yIndex, ThreePoint *resultPoint);
- static void WaterPlotLine(ThreePoint *startPoint, ThreePoint *endPoint);
-
- /* Global variables */
- long gMaxX, gMaxY;
- long gLevel; /* Current level */
- unsigned char gCurPixelColor; /* Pixel value for offscreen line drawing */
- unsigned char gDBluePixelColor;
- unsigned char gLBluePixelColor;
- unsigned char gBlackPixelColor;
- char* gPixelBase; /* Base of pixel store */
- long gRowBytesIncrement; /* Amount to increment each offscreen row */
- char gGrayColors[kTotalGrays];/* Gray color table */
-
- /* Macros */
- #define AbsoluteValue(v) ((v) >= 0 ? (v) : -(v))
- #define ConvertToShadeIndex(x) ((x >= kShadeMapSize) ? (kShadeMapSize - 1) : x)
-
-
- /*
- RandomDouble
-
- This function returns a random number between -1 and 1.
- */
- double RandomDouble(void)
- {
- return (double)rand() / RAND_MAX;
- }
-
-
- /*
- CalcSurface
-
- This is the main surface-generating routine. It generates a random
- fractal surface by filling in the gPointArray array.
- */
- void CalcSurface(unsigned short level)
- {
- long i, j, length, incrby, sk;
- float power;
- UnsignedWide startTime, endTime;
-
- if (gMorphFractal)
- gMorphAmount = 0.0;
- else
- gMorphAmount = 1.0;
- gLevel = level;
-
- gTotalFractals++;
- gFractalChanged = true;
- Microseconds(&startTime);
-
- gMaxX = 1 << level;
- gMaxY = gMaxX / 2;
- for (i = 0; i <= gMaxX; i++) /* Clear the Array. Use i & incrby as temps */
- for (incrby = 0; incrby <= gMaxY; incrby++)
- (*gNewPointArray)[i][incrby] = 0;
-
- for (i = 1; i <= level; i++) {
- for (power = 1.0, j = 0; j < i; j++) {
- if (gContourType == kStyleMountains)
- power *= 1.5 + (level / 40.0); /* Mountains must be bumpier than the other styles */
- else
- power *= 1.8 + (level / 40.0);
- }
- length = 10000 / power; /* = 10000/(1.8^i) */
- incrby = gMaxX / (1 << i); /* # of line segments in a side of the triangle */
- sk = incrby * 2;
- CalcXs(length, incrby, sk);
- CalcYs(length, incrby, sk);
- CalcDiagonals(length, incrby, sk);
- }
-
- Microseconds(&endTime);
- if (startTime.hi == endTime.hi)
- gMicrosecondCount += endTime.lo - startTime.lo;
- else
- gMicrosecondCount += startTime.lo - endTime.lo;
- }
-
-
- /*
- CalcXs
-
- This function calculates the fractal values in the X direction.
- It is called for each level and subdivides the existing edges
- of the fractal to get the next level.
- */
- void CalcXs(long len, long incr, long sk)
- {
- long y, x;
- long d1, d2;
-
- for (y=0; y < gMaxX; y += sk) {
- for (x = incr+y; x <= gMaxX; x += sk) {
- d1 = GetZValue(x-incr, y);
- d2 = GetZValue(x+incr, y);
- SetZValue(((d1 + d2) >> 1) + (long)(RandomDouble() * (len >> 1)) - (len >> 2), x, y);
- }
- }
- }
-
-
- /*
- CalcYs
-
- This function calculates the fractal values in the Y direction.
- It is called for each level and subdivides the existing edges
- of the fractal to get the next level.
- */
- void CalcYs(long len, long incr, long sk)
- {
- long y, x;
- long d1, d2;
-
- for (x = gMaxX; x >= 1; x -= sk)
- for (y = incr; y <= x; y += sk) {
- d1 = GetZValue(x, y + incr);
- d2 = GetZValue(x, y - incr);
- SetZValue(((d1 + d2) >> 1) + (long)(RandomDouble() * (len >> 1)) - (len >> 2), x, y);
- }
- }
-
-
- /*
- CalcDiagonals
-
- This function calculates the fractal values in the diagonal direction.
- It is called for each level and subdivides the existing edges
- of the fractal to get the next level.
- */
- void CalcDiagonals(long len, long incr, long sk)
- {
- long y, x;
- long d1, d2;
-
- for (x = 0; x < gMaxX; x += sk)
- for (y = incr; y <= gMaxX - x; y += sk) {
- d1 = GetZValue(x + y - incr, y - incr);
- d2 = GetZValue(x + y + incr, y + incr);
- SetZValue(((d1 + d2) >> 1) + (long)(RandomDouble() * (len >> 1)) - (len >> 2), x + y, y);
- }
- }
-
-
- /*
- GetZValue
-
- This function returns the Z value (i.e. the value stored in the
- two-dimensional gPlotArray array. Because the fractal is triangular
- and the array is square, we will store half the triange in the lower
- part of the array the the other half in the upper part of the
- array.
- */
- long GetZValue(long x, long y)
- {
- if (y <= gMaxY)
- return (*gNewPointArray)[x][y];
- else
- return (*gNewPointArray)[gMaxX - x][gMaxX + 1 - y];
- }
-
-
- /*
- SetZValue
-
- This function saves the Z value (i.e. the value in the
- two-dimensional gPlotArray array. Because the fractal is triangular
- and the array is square, we will store half the triange in the lower
- part of the array the the other half in the upper part of the
- array.
- */
- void SetZValue(long d, long x, long y)
- {
- if (y <= gMaxY)
- (*gNewPointArray)[x][y] = d;
- else
- (*gNewPointArray)[gMaxX - x][gMaxX + 1 - y] = d;
- }
-
-
- /*
- Transform1Point
-
- This function transforms a single XY point and stores
- returns its XY coordinate as well as its scaled three-
- space Z coordinate into the result structure.
- */
- void Transform1Point(long xIndex, long yIndex, ThreePoint *resultPoint)
- {
- long newComponent,
- oldComponent;
- long componentShift;
- long xComponent, yComponent;
- long yResult, zResult;
-
- componentShift = kMaxLevel + 1 - gContourLevel;
- xComponent = xIndex << componentShift;
- yComponent = yIndex << componentShift;
-
- resultPoint->x = xComponent + yComponent + kXOrigin;
- if (gContourType == kStyleMountains)
- yResult = -xComponent + yComponent + kYMountainOrigin;
- else
- yResult = xComponent + -yComponent + kYOrigin;
-
- if (gMorphFractal) {
- newComponent = (((yIndex <= gMaxY) ? (*gNewPointArray)[xIndex][yIndex] :
- (*gNewPointArray)[gMaxX - xIndex][gMaxX + 1 - yIndex])) * gMorphAmount;
-
- oldComponent = (((yIndex <= gMaxY) ? (*gOldPointArray)[xIndex][yIndex] :
- (*gOldPointArray)[gMaxX - xIndex][gMaxX + 1 - yIndex])) * gMorphAmountNeg;
-
- zResult = newComponent + oldComponent;
- }
- else {
- zResult = (((yIndex <= gMaxY) ? (*gNewPointArray)[xIndex][yIndex] :
- (*gNewPointArray)[gMaxX - xIndex][gMaxX + 1 - yIndex]));
- }
-
- yResult -= (zResult >> kScaleShift);
- resultPoint->y = yResult;
- resultPoint->z = zResult;
- }
-
-
- /*
- PlotData
-
- Our window is already open at this point, and it is cleared.
- All we have to do now is fill it. This function draws the
- 2D projection of the triangular database on the screen.
- */
- void PlotData(Boolean plotSurface)
- {
- long xindex, yindex;
-
- gMorphAmountNeg = (1.0 - gMorphAmount);
-
- if (plotSurface)
- SetGrayValues();
-
- gPixelBase = (char*)GetPixBaseAddr(gOffscreenPixMap);
- gRowBytesIncrement = (*gOffscreenPixMap)->rowBytes & 0x7FFF;
-
- gDBluePixelColor = GetLineColor(0, 0xFFFF, 0);
- gLBluePixelColor = GetLineColor(0x3FFF, 0xFFFF, 0x3FFF);
- gCurPixelColor = gBlackPixelColor = GetLineColor(0, 0, 0);
-
- if (!plotSurface) {
- for (xindex = 1; xindex <= gMaxX; xindex++) {
- for (yindex = 0; yindex <= xindex; yindex++)
- Transform1Point(xindex, yindex, &((*gPlotPointArray)[xindex][yindex]));
- }
-
- for (xindex = 0; xindex < gMaxX; xindex++) {
- for (yindex = xindex - 1; yindex >= 0; yindex--) {
-
- ThreePoint *currentPoint1,
- *currentPoint2,
- *currentPoint3;
-
- currentPoint1 = &((*gPlotPointArray)[xindex][yindex]);
- currentPoint2 = &((*gPlotPointArray)[xindex + 1][yindex]);
- currentPoint3 = &((*gPlotPointArray)[xindex + 1][yindex + 1]);
-
- if (gContourType == kStyleWater) {
- WaterPlotLine(currentPoint1, currentPoint2);
- WaterPlotLine(currentPoint2, currentPoint3);
- WaterPlotLine(currentPoint3, currentPoint1);
- }
- else {
- LineToOffscreen(currentPoint1->x, currentPoint1->y, currentPoint2->x, currentPoint2->y);
- LineToOffscreen(currentPoint2->x, currentPoint2->y, currentPoint3->x, currentPoint3->y);
- LineToOffscreen(currentPoint3->x, currentPoint3->y, currentPoint1->x, currentPoint1->y);
- }
- }
-
- }
- }
- else {
-
- SetBlitBuffer((unsigned char *)gPixelBase, NULL, gRowBytesIncrement);
-
- for (xindex = 1; xindex <= gMaxX; xindex++) {
- for (yindex = 0; yindex <= xindex; yindex++) {
- Transform1Point(xindex, yindex, &((*gPlotPointArray)[xindex][yindex]));
- }
- }
-
- for (xindex = 0; xindex < gMaxX; xindex++) {
- for (yindex = xindex - 1; yindex >= 0; yindex--) {
-
- ThreePoint *currentPoint1,
- *currentPoint2,
- *currentPoint3;
-
- long vertex1H, vertex1V;
- long vertex2H, vertex2V;
- long vertex3H, vertex3V;
- long diff1, diff2, diffTotal;
- unsigned char color;
-
- currentPoint1 = &((*gPlotPointArray)[xindex][yindex]);
-
- vertex1H = currentPoint1->x;
- vertex1V = currentPoint1->y;
-
- currentPoint2 = &((*gPlotPointArray)[xindex + 1][yindex]);
-
- vertex2H = currentPoint2->x;
- vertex2V = currentPoint2->y;
-
- currentPoint3 = &((*gPlotPointArray)[xindex + 1][yindex + 1]);
-
- vertex3H = currentPoint3->x;
- vertex3V = currentPoint3->y;
-
- color = 0;
-
- if (gContourType == kStyleWater) {
-
- if (currentPoint1->z <= 0) {
- vertex1V += currentPoint1->z >> kScaleShift;
- color = gDBluePixelColor;
- }
-
- if (currentPoint2->z <= 0) {
- vertex2V += currentPoint2->z >> kScaleShift;
- color = gDBluePixelColor;
- }
-
- if (currentPoint3->z <= 0) {
- vertex3V += currentPoint3->z >> kScaleShift;
- color = gDBluePixelColor;
- }
-
- }
-
- if (color != gDBluePixelColor) {
-
- diff1 = currentPoint1->z - currentPoint2->z;
- if (diff1 < 0)
- diff1 = -diff1;
-
- diff2 = currentPoint3->z - currentPoint2->z;
- if (diff2 < 0)
- diff2 = -diff2;
-
- diffTotal = (diff1 + diff2) >> (kMaxLevel + 3 - gContourLevel);
-
- color = gGrayColors[gShadeMap[ConvertToShadeIndex(diffTotal)]];
-
- }
-
- FillTriangle(vertex1H, vertex1V,
- vertex2H, vertex2V,
- vertex3H, vertex3V,
- color);
-
- if (yindex < xindex - 1) {
-
- currentPoint2 = &((*gPlotPointArray)[xindex][yindex + 1]);
-
- vertex2H = currentPoint2->x;
- vertex2V = currentPoint2->y;
-
- color = 0;
-
- if (gContourType == kStyleWater) {
-
- if (currentPoint1->z <= 0)
- color = gLBluePixelColor;
-
- if (currentPoint2->z <= 0) {
- vertex2V += currentPoint2->z >> kScaleShift;
- color = gLBluePixelColor;
- }
-
- if (currentPoint3->z <= 0)
- color = gLBluePixelColor;
-
- }
-
- if (color != gLBluePixelColor) {
-
- diff1 = currentPoint1->z - currentPoint2->z;
- if (diff1 < 0)
- diff1 = -diff1;
-
- diff2 = currentPoint3->z - currentPoint2->z;
- if (diff2 < 0)
- diff2 = -diff2;
-
- diffTotal = (diff1 + diff2) >> (kMaxLevel + 3 - gContourLevel);
-
- color = gGrayColors[gShadeMap[ConvertToShadeIndex(diffTotal)]];
-
- }
-
- FillTriangle(vertex1H, vertex1V,
- vertex2H, vertex2V,
- vertex3H, vertex3V,
- color);
-
- }
- }
- }
- }
- }
-
-
- /*
- WaterPlotLine
- */
- void WaterPlotLine(ThreePoint *startPoint, ThreePoint *endPoint)
- {
- if (startPoint->z <= 0) {
- PointOffscreen(startPoint->x, startPoint->y + (startPoint->z >> kScaleShift), gDBluePixelColor);
- if (endPoint->z <= 0)
- PointOffscreen(endPoint->x, endPoint->y + (endPoint->z >> kScaleShift), gDBluePixelColor);
- }
- else if (endPoint->z <= 0)
- PointOffscreen(endPoint->x, endPoint->y + (endPoint->z >> kScaleShift), gDBluePixelColor);
- else
- LineToOffscreen(startPoint->x, startPoint->y, endPoint->x, endPoint->y);
- }
-
-
- /*
- GetLineColor
-
- This function returns the pixel value for the given
- RGB color.
- */
- unsigned char GetLineColor(unsigned short red, unsigned short blue, unsigned short green)
- {
- RGBColor curColor;
-
- curColor.red = red;
- curColor.blue = blue;
- curColor.green = green;
- return Color2Index(&curColor);
- }
-
-
- /*
- SetGrayValues
- */
- void SetGrayValues(void)
- {
- long curGrayIndex;
- long curGrayValue;
- long grayIncrement;
- RGBColor curColor;
-
- grayIncrement = (1<<15) / (kTotalGrays - 1);
- curGrayValue = 32767;
- for (curGrayIndex = 0; curGrayIndex < kTotalGrays; curGrayIndex++) {
- curColor.red = curColor.blue = curColor.green = curGrayValue;
- gGrayColors[curGrayIndex] = Color2Index(&curColor);
- curGrayValue += grayIncrement;
- }
- }
-
-
- /*
- LineToOffscreen
-
- This function replaces the LineTo function with a custom
- off-screen line drawing function.
- */
- void LineToOffscreen(long sX, long sY, long eX, long eY)
- {
- if (AbsoluteValue(eY - sY) > AbsoluteValue(eX - sX)) {
- if (eY < sY)
- LineYOffscreen(eX, eY, sX, sY);
- else
- LineYOffscreen(sX, sY, eX, eY);
- }
- else {
- if (eX < sX)
- LineXOffscreen(eX, eY, sX, sY);
- else
- LineXOffscreen(sX, sY, eX, eY);
- }
- }
-
-
- /*
- LineXOffscreen
-
- Draws lines with a slope between -1 and 1
- */
- void LineXOffscreen(long startX, long startY, long endX, long endY)
- {
- char* pixelAddress;
- unsigned char localColor = gCurPixelColor;
- long localRowBytes = gRowBytesIncrement;
- long currentX;
-
- if (endX == startX) {
- pixelAddress = gPixelBase + startX + (unsigned long)(startY * localRowBytes);
- for (currentX = startX; currentX <= endX; currentX++)
- *pixelAddress++ = localColor;
- }
- else {
- long newY;
- long slope, currentY;
-
- slope = ((endY - startY) << 16) / (endX - startX);
-
- pixelAddress = gPixelBase + startX + (unsigned long)(startY * localRowBytes) - 1;
- currentY = (startY << 16) + (1 << 15);
-
- if (endY > startY) {
- for (currentX = startX; currentX <= endX; currentX++, currentY = newY) {
- newY = currentY + slope;
- *++pixelAddress = localColor;
- if ((newY >> 16) > (currentY >> 16))
- pixelAddress += localRowBytes;
- }
- }
- else {
- for (currentX = startX; currentX <= endX; currentX++, currentY = newY) {
- newY = currentY + slope;
- *++pixelAddress = localColor;
- if ((currentY >> 16) > (newY >> 16))
- pixelAddress -= localRowBytes;
- }
- }
- }
- }
-
-
- /*
- LineYOffscreen
-
- Draws lines with a slope <= -1 or >= 1
- */
- void LineYOffscreen(long startX, long startY, long endX, long endY)
- {
- long currentY;
- char* pixelAddress;
- unsigned char localColor = gCurPixelColor;
- long localRowBytes = gRowBytesIncrement;
-
- if (endY == startY) {
- pixelAddress = gPixelBase + startX + (unsigned long)(startY * localRowBytes);
- for (currentY = startY; currentY <= endY; currentY++) {
- *pixelAddress = localColor;
- pixelAddress += localRowBytes;
- }
- }
- else {
- long newX;
- long slope, currentX;
-
- slope = ((endX - startX) << 16) / (endY - startY);
-
- pixelAddress = gPixelBase + startX + (unsigned long)(startY * localRowBytes);
- currentX = (startX << 16) + (1 << 15);
-
- if (endX > startX) {
- for (currentY = startY; currentY <= endY; currentY++, currentX = newX) {
- newX = currentX + slope;
- *pixelAddress = localColor;
- pixelAddress += localRowBytes;
- if ((newX >> 16) - (currentX >> 16))
- pixelAddress++;
- }
- }
- else {
- for (currentY = startY; currentY <= endY; currentY++, currentX = newX) {
- newX = currentX + slope;
- *pixelAddress = localColor;
- pixelAddress += localRowBytes;
- if ((currentX >> 16) - (newX >> 16))
- pixelAddress--;
- }
- }
- }
- }
-
-
- /*
- PointOffscreen
-
- Draws a single pixel
- */
- void PointOffscreen(long x, long y , unsigned char colorValue)
- {
- char* pixelAddress;
-
- pixelAddress = gPixelBase + x;
- pixelAddress += (unsigned long)(y * gRowBytesIncrement);
- *pixelAddress = colorValue;
- }
-
-
-
-
-
-
-
-